Introduction and Background
Agenda
Part I - Setting up the Data
- Define the differences between Metabarcoding/Amplicon sequencing and Whole Shotgun Sequencing Metagenomics
- Get some practice in RStudio OnDemand and using the Tufts Cluster
- Learn about accessing interesting NCBI data through BioProjects and SRA Run Selector
- Refine our quality control best practices to preprocess data we have generated or downloaded
- Fastqc
- Multiqc
- Kmer-based filtering and trimming with BCBio tools
This Metagenomics Tutorial is mainly a set of Bash Commands
This tutorial uses code chunks. To run an individual code chunk while the notebook is open in OnDemand RStudio, please press the green triangle on the upper right corner of the code chunk.
You may be wondering why we went through the trouble of having bash commands inside an R notebook for this tutorial. The simplest answer is that RStudio has the handy ability to open visualization files with a simple click on the file name in the lower right screen. This saves a lot of time and confusing navigation when doing this type of project, that produces a lot of intermediate files.
RStudio can run code chunks in other languages by resetting the code chunks to read that language.
{bash} indicates that the code chunk is in command line syntax, so these commands can be copied and pasted directly into a terminal
{r} indicates that the code chunk uses R-code
To save a bunch of copying/pasting, we are just going to run both types of these chunks inside our notebook using RStudio OnDemand.
The order of chunks is important, so if you skip one or get lost, it is possible to use the dropdown menu next to the word “Run” at the top of this window to run multiple chunks to get you back to where you started.
Any questions?
What other “kernels” are available in R notebook code chunks? (Hint - click the down arrow next to the "Insert Chunk command at the top of this window)
Attach public library paths to your RStudio OnDemand session
The setup code adds the libraries in the order they will be searced for packages.
Setting .libpaths() to Tufts shared folders can reduce the amount of time spent downloading packages.
Please reach out to us about any difficult or tricky installs, sometimes it is a library package error that has to be fixed by an TTS HPC Research Technology Specialist.
Please make sure that the output to this code chunk has the shared library, “/cluster/tufts/hpc/tools/R/4.0.0” in position [1]
Example output (it depends what else you have been doing in RStudio before today).
[1] “/cluster/tufts/hpc/tools/R/4.0.0” [2] “/cluster/home/arhode05/R/x86_64-pc-linux-gnu-library/4.0” [3] “/opt/shared/R/4.0.0/lib64/R/library”
Commands to specify the shared directory as the first place to look for R libraries and check the output.
.libPaths(c('/cluster/tufts/hpc/tools/R/4.0.0',.libPaths()))
.libPaths()
Modules and Conda Environments
In this workshop, we will sometimes be loading modules from the HPC to use in a code chunk.
Here is an example code chunk that loads a module for samtools and runs the command with the help flag to generate some output to test that the module loaded correctly.
If the bash environment is not designated in the setup chunk, you may need to add this bash command at the beginning of the chunk to enable module loading.
source ~/.bashrc
The behavior of modules in the code chunks differs from our direct command line.
The Rmarkdown notebook will not remember it from chunk to chunk. So load the modules in the chunks where the commands are needed.
An example with conda environments will be shown in Part II.
What happens when you run this chunk?
module list
Why use modules instead of conda environments?
Conda environments are great for installing specific versions of programs, but often bring in clashing dependencies, and only one is active at a time.
Using HPC modules can provide more integration because you can load several at one time.
Of course, conda environments could be used if you load all the required programs into the same environment. We will see an example of this later with Metawrap
Introducing the Data - Giant Panda ticks
Ticks are capable of spreading pathogens (viruses, bacteria and other parasites) among a host population. Not much is known about the spread of tick-borne viruses in Giant Pandas. The density of giant pandas in breeding captivity in Sichuan Province, China may lead to more transmission of these diseases. The researchers who loaded this data into the SRA were interested in characterizing the virome of these ticks and to compare these with the virome of the pandas.
We are not going to restrict our analysis to the virome, and just take a general look at what these ticks are carryng around in general using practical metagenomics workflows.
Check out the bioproject here
Check out the final paper here
We are going to bring in some of the data from this bioproject to our Metagenomics Tutorial space.
Obtaining Data from SRA
The data we are going to copy over can be obtained directly from the SRA by using our command line module for the SRAToolkit. This can take a little while, depending on the internet connection and which source the files are pulled from (on-prem, AWS or GCP).
“Spots” in SRA are not the same as “reads”
- A spot is all the info you got from one “spot” on the flow cell.
- You get 4 reads per spot with today’s illumina sequencing: forward barcode, forward read, reverse barcode, reverse read.
Practice downloading data from SRA
module load /cluster/tufts/bio/tools/module_files/sra/3.0.0
mkdir -p test_SRA
fastq-dump --outdir test_SRA -X 500 --skip-technical --read-filter pass --readids --minReadLen 200 --split-e SRR18086364
Command Line Parameters
- Grap first million lines
-X 500
- Only “biological reads”
--skip-technical
- Remove reads that are mostly N’s
--read-filter pass
- Append
.1 to forward read header .2 to reverse read header –readids
- Keep mated pairs and singletons, use -–split-e and a three files will be generated if orphans are present (forward, reverse, and unmatched mates)
There should be three new files in your Metagenomics2022/test_SRA directory.
The output is small enough that we can look into the fastq file by clicking on it.
- Confirm the
.1 and .2 were appended to your forward read headers and reverse read headers
- What happened inside the singleton file? Do you see
.1, .2 or both?
- QC Best practice: Count the number of lines in the output files
wc -l ./test_SRA/*.fastq
How many lines are in our fastq output files and why?
(Hint 1: we asked for 500 “spots”, not reads) (Hint 2: how did our parameter choices affect our outputs?)
A Note about Fasterq-dump
In some cases, the newer version of this tool fasterq-dump will automatically run the split-e version of the command without adding this parameter. It is worth looking at the options before using it, because some of the parameter meanings have changed.
The following codeblock is for reference, to use the chunk, remove the # at the beginning of the line.
#/cluster/tufts/hpc/tools/spack/linux-rhel7-ivybridge/gcc-9.3.0/fastqc-0.11.9-eeij5jwnwau3ttx4m53bxafmxbhm4fjz/bin/fastqc ./MGData/*overrep.fastq
source ~/.bashrc
module load fastqc
mkdir -p fastqc
fastqc ./data/*pass*.fastq -o fastqc
#source ~/.bashrc
module load multiqc/1.7.0
mkdir -p multiqc
multiqc ./fastqc -o ./multiqc
Check the quality of your results by navigating to the file folder for multiqc and clicking on the html files that were generated.
Okay, so the data is not the most perfect, but we just need a set that can make it through the analysis.
Preprocessing Reads
Metagenomics has benefited from k-mer based approaches.
|||| Add descriptioin of k-mer based approaches here ||||
BCBio tools are useful for cleaining metagenomics files, because many simple functions can be called and sped up using kmers.
For example, let’s remove known adapter and other contamination using the NCBI database called “UniVec”
||||| Adding more information about UniVec here |||||||
cd ~/Metagenomics2022
#pwd
#grep "TruSeq" ./data/UniVec.fasta
grep "PCR Primer Index 9" ./data/UniVec.fasta
Part II
Running an Assembly on the Cleaned Data
What is a deBruijn graph?
It is an assembly algorithm that splits your sequence into k-mers and tries to build the longest contigs along the shortest parsimonious path.
To save time in the workshop, the assembly has been done using the commented out command above and placed into your workshop folder called “reports”.
Checking the quality of our Assembly
Quast is a commonly used tool to assess assemblies. It will provide a report that is either in a text file or an html.
Let’s run the following command and then look for the quast report to see if we have a “good” assembly.
/cluster/tufts/bio/tools/quast/5.2.0/quast.py -o quast_assembly ./reports/final.contigs.fa
What can we do with Metagenomic Approaches
Case Study: Describing a Complete Cyanobacterial Genome and its Symbionts from an Extremely Arid Environment
The Atacama Desert - Are we on Mars?
So we are probably running out of time to continue working hands on.
Let’s take some time to discuss what the next steps might look like.
This discussion will center around a recent project from Dr. Pearson’s lab, conducted by Neveda Naz, Ph.D.
Neveda builds little robots and sends them to outerspace. (Neveda if you are here, feel free to comment!)
Please open up this pdf here to find the discussion.
Helpful Resources
Also, for future reading, I have placed two useful .pdf’s in our public github pages that summarize the steps we are discussing in further detail.
Essentials in Metagenomics I Essentials in Metagenomics II
This markdown and associated files will be placed in our Github and mailed out to the class shortly.
We will also send out a video of this workshop.
Please Provide Feedback
Jason and I hope to continue developing this practical material to provide more hands-on experience in the future, so any feedback on the tools you would like to explore is appreciated.
LS0tCnRpdGxlOiAiTWV0YWdlbm9taWNzIFdvcmtzaG9wLCBOb3ZlbWJlciA5LCAyMDIyIgphdXRob3I6ICJBZGVsYWlkZSBSaG9kZXMgUGguRC4iCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIGRmX3ByaW50OiBwYWdlZAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwotLS0KCiMjIEludHJvZHVjdGlvbiBhbmQgQmFja2dyb3VuZAoKIyMjIEFnZW5kYQoKIyMjIyBQYXJ0IEkgLSBTZXR0aW5nIHVwIHRoZSBEYXRhCgoqIERlZmluZSB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBNZXRhYmFyY29kaW5nL0FtcGxpY29uIHNlcXVlbmNpbmcgYW5kIFdob2xlIFNob3RndW4gU2VxdWVuY2luZyBNZXRhZ2Vub21pY3MKKiBHZXQgc29tZSBwcmFjdGljZSBpbiBSU3R1ZGlvIE9uRGVtYW5kIGFuZCB1c2luZyB0aGUgVHVmdHMgQ2x1c3RlcgoqIExlYXJuIGFib3V0IGFjY2Vzc2luZyBpbnRlcmVzdGluZyBOQ0JJIGRhdGEgdGhyb3VnaCBCaW9Qcm9qZWN0cyBhbmQgU1JBIFJ1biBTZWxlY3RvcgoqIFJlZmluZSBvdXIgcXVhbGl0eSBjb250cm9sIGJlc3QgcHJhY3RpY2VzIHRvIHByZXByb2Nlc3MgZGF0YSB3ZSBoYXZlIGdlbmVyYXRlZCBvciBkb3dubG9hZGVkCisgRmFzdHFjCisgTXVsdGlxYworIEttZXItYmFzZWQgZmlsdGVyaW5nIGFuZCB0cmltbWluZyB3aXRoIEJDQmlvIHRvb2xzCgojIyMjIFBhcnQgSUkgLSBQcmFjdGljZSBhIHR5cGljYWwgbWV0YWdlbm9taWMgd29ya2Zsb3cKCisgTWV0YWdlbm9tZSBBc3NlbWJseSB3aXRoIE1lZ2FoaXQKKyBBc3Nlc3NpbmcgdGhlIFF1YWxpdHkgb2YgYW4gQXNzZW1ibHkgd2l0aCBRdWFzdAorIFByZWxpbWluYXJ5IGNvbnRhbWluYXRpb24gc2NyZWVuaW5nIHdpdGgga3Jha2VuCisgVmlzdWFsaXphdGlvbiBvZiBrcmFrZW4gcmVwb3J0cyB3aXRoIHRoZSBrcm9uYSB0b29sCgoKVGhlIGZvbGxvd2luZyBpdGVtcyBhcmUgbm90IGhhbmRzIG9uLCBidXQgd2lsbCBiZSBzaG93biBhcyBwYXJ0IG9mICB1c2UgY2FzZSBvZiBhIHJlY2VudCBNZXRhZ2Vub21pY3MgV29ya2Zsb3cgZG9uZSBpbiBjb2xsYWJvcmF0aW9uIHdpdGggYSBUdWZ0cyBSZXNlYXJjaGVyCgorIE1ldGFnZW5vbWUgQmlubmluZyBhbmQgUmVmaW5lbWVudCB3aXRoIE1ldGFCYXQyLCBNYXhCaW4gYW5kIENvbmNvY3QKKyBWaXN1YWxpemF0aW9uIG9mIFNlcXVlbmNlIG9mIE1ldGFnZW5vbWljIEJpbnMgd2l0aCBCbG9iVG9vbHMKKyBFeHRyYWN0aW5nIFJlbGV2YW50IFJlYWRzIHdpdGggQldBCisgUmVhc3NlbWJseSB3aXRoIE1lZ2FoaXQgZnJvbSB0aGUgQmlucworIFRheG9ub21pYyBDbGFzc2lmaWNhdGlvbiB3aXRoIEthaWp1CisgRnVuY3Rpb25hbCBDbGFzc2lmaWNhdGlvbiB3aXRoIFByb2trYQoKSWYgdGhpcyBzb3VuZHMgbGlrZSBhIGxvdCBvZiBncm91bmQgdG8gY292ZXIsIHlvdSBhcmUgY29ycmVjdCEKCkluIHNvbWUgcG9ydGlvbnMgb2YgdGhpcyB0dXRvcmlhbCwgd2UgZG9uJ3QgYWN0dWFsbHkgcnVuIHRoZSBjb2RlLCBidXQganVtcCBhaGVhZCB0byB0aGUgbmV4dCBzdGVwLgoKRm9yIHRoZXNlICJza2lwcGVkIiBwb3J0aW9ucywgdGhlIGNvZGUgdG8gcnVuIHRoZSBwcm9jZXNzIGlzIHByb3ZpZGVkLgoKCiMjIyBUaGlzIE1ldGFnZW5vbWljcyBUdXRvcmlhbCBpcyBtYWlubHkgYSBzZXQgb2YgQmFzaCBDb21tYW5kcwoKVGhpcyB0dXRvcmlhbCB1c2VzIGNvZGUgY2h1bmtzLiBUbyBydW4gYW4gaW5kaXZpZHVhbCBjb2RlIGNodW5rIHdoaWxlIHRoZSBub3RlYm9vayBpcyBvcGVuIGluIE9uRGVtYW5kIFJTdHVkaW8sIHBsZWFzZSBwcmVzcyB0aGUgZ3JlZW4gdHJpYW5nbGUgb24gdGhlIHVwcGVyIHJpZ2h0IGNvcm5lciBvZiB0aGUgY29kZSBjaHVuay4KCgpgYGB7ciBzZXR1cCBjb21tYW5kcywgc2V0dXAsIGluY2x1ZGU9RkFMU0V9CgojVGhpcyBjb21tYW5kIHNldHMgb3VyIHdvcmtpbmcgZGlyZWN0b3J5IHRvIHRoaXMgd29ya3Nob3AKa25pdHI6Om9wdHNfa25pdCRzZXQocm9vdC5kaXIgPSAnfi9NZXRhZ2Vub21pY3MyMDIyJykKCiNUaGUgbmV4dCB0d28gbGluZXMgbWFrZXMgb3VyIGJhc2ggcHJvZmlsZSB2aXNpYmxlIHRvIHRoZSBSIGVudmlyb25tZW50LCBhbGxvd2luZyB0aGUgdXNlIG9mIG1vZHVsZXMuCmtuaXRyOjpvcHRzX2NodW5rJHNldChlbmdpbmUub3B0cyA9IGxpc3QoYmFzaCA9ICItbCIpKQpTeXMuc2V0ZW52KEJBU0hfRU5WPSJ+Ly5iYXNocmMiKQoKYGBgCgpZb3UgbWF5IGJlIHdvbmRlcmluZyB3aHkgd2Ugd2VudCB0aHJvdWdoIHRoZSB0cm91YmxlIG9mIGhhdmluZyBiYXNoIGNvbW1hbmRzIGluc2lkZSBhbiBSIG5vdGVib29rIGZvciB0aGlzIHR1dG9yaWFsLiBUaGUgc2ltcGxlc3QgYW5zd2VyIGlzIHRoYXQgUlN0dWRpbyBoYXMgdGhlIGhhbmR5IGFiaWxpdHkgdG8gb3BlbiB2aXN1YWxpemF0aW9uIGZpbGVzIHdpdGggYSBzaW1wbGUgY2xpY2sgb24gdGhlIGZpbGUgbmFtZSBpbiB0aGUgIGxvd2VyIHJpZ2h0IHNjcmVlbi4gVGhpcyBzYXZlcyBhIGxvdCBvZiB0aW1lIGFuZCBjb25mdXNpbmcgbmF2aWdhdGlvbiB3aGVuIGRvaW5nIHRoaXMgdHlwZSBvZiBwcm9qZWN0LCB0aGF0IHByb2R1Y2VzIGEgbG90IG9mIGludGVybWVkaWF0ZSBmaWxlcy4KClJTdHVkaW8gY2FuIHJ1biBjb2RlIGNodW5rcyBpbiBvdGhlciBsYW5ndWFnZXMgYnkgcmVzZXR0aW5nIHRoZSBjb2RlIGNodW5rcyB0byByZWFkIHRoYXQgbGFuZ3VhZ2UuCgoqICAgYHtiYXNofWAgaW5kaWNhdGVzIHRoYXQgdGhlIGNvZGUgY2h1bmsgaXMgaW4gY29tbWFuZCBsaW5lIHN5bnRheCwgc28gdGhlc2UgY29tbWFuZHMgY2FuIGJlIGNvcGllZCBhbmQgcGFzdGVkIGRpcmVjdGx5IGludG8gYSB0ZXJtaW5hbAoKKiAgIGB7cn1gIGluZGljYXRlcyB0aGF0IHRoZSBjb2RlIGNodW5rIHVzZXMgUi1jb2RlCiAgICAKVG8gc2F2ZSBhIGJ1bmNoIG9mIGNvcHlpbmcvcGFzdGluZywgd2UgYXJlIGp1c3QgZ29pbmcgdG8gcnVuIGJvdGggdHlwZXMgb2YgdGhlc2UgY2h1bmtzIGluc2lkZSBvdXIgbm90ZWJvb2sgdXNpbmcgUlN0dWRpbyBPbkRlbWFuZC4KClRoZSBvcmRlciBvZiBjaHVua3MgaXMgaW1wb3J0YW50LCBzbyBpZiB5b3Ugc2tpcCBvbmUgb3IgZ2V0IGxvc3QsIGl0IGlzIHBvc3NpYmxlIHRvIHVzZSB0aGUgZHJvcGRvd24gbWVudSBuZXh0IHRvIHRoZSB3b3JkICJSdW4iIGF0IHRoZSB0b3Agb2YgdGhpcyB3aW5kb3cgdG8gcnVuIG11bHRpcGxlIGNodW5rcyB0byBnZXQgeW91IGJhY2sgdG8gd2hlcmUgeW91IHN0YXJ0ZWQuCgpBbnkgcXVlc3Rpb25zPwoKLS0tCgojIyMjIyBXaGF0IG90aGVyICJrZXJuZWxzIiBhcmUgYXZhaWxhYmxlIGluIFIgbm90ZWJvb2sgY29kZSBjaHVua3M/IChIaW50IC0gY2xpY2sgdGhlIGRvd24gYXJyb3cgbmV4dCB0byB0aGUgIkluc2VydCBDaHVuayBjb21tYW5kIGF0IHRoZSB0b3Agb2YgdGhpcyB3aW5kb3cpCgotLS0KCiMjIyBBdHRhY2ggcHVibGljIGxpYnJhcnkgcGF0aHMgdG8geW91ciBSU3R1ZGlvIE9uRGVtYW5kIHNlc3Npb24KClRoZSBzZXR1cCBjb2RlIGFkZHMgdGhlIGxpYnJhcmllcyBpbiB0aGUgb3JkZXIgdGhleSB3aWxsIGJlIHNlYXJjZWQgZm9yIHBhY2thZ2VzLiAKClNldHRpbmcgYC5saWJwYXRocygpYCB0byBUdWZ0cyBzaGFyZWQgZm9sZGVycyBjYW4gcmVkdWNlIHRoZSBhbW91bnQgb2YgdGltZSBzcGVudCBkb3dubG9hZGluZyBwYWNrYWdlcy4gCgoqKlBsZWFzZSByZWFjaCBvdXQgdG8gdXMgYWJvdXQgYW55IGRpZmZpY3VsdCBvciB0cmlja3kgaW5zdGFsbHMsIHNvbWV0aW1lcyBpdCBpcyBhIGxpYnJhcnkgcGFja2FnZSBlcnJvciB0aGF0IGhhcyB0byBiZSBmaXhlZCBieSBhbiBUVFMgSFBDIFJlc2VhcmNoIFRlY2hub2xvZ3kgU3BlY2lhbGlzdC4qKgoKUGxlYXNlIG1ha2Ugc3VyZSB0aGF0IHRoZSBvdXRwdXQgdG8gdGhpcyBjb2RlIGNodW5rIGhhcyB0aGUgc2hhcmVkIGxpYnJhcnksICIvY2x1c3Rlci90dWZ0cy9ocGMvdG9vbHMvUi80LjAuMCIgIGluIHBvc2l0aW9uIFsxXQoKRXhhbXBsZSBvdXRwdXQgKGl0IGRlcGVuZHMgd2hhdCBlbHNlIHlvdSBoYXZlIGJlZW4gZG9pbmcgaW4gUlN0dWRpbyBiZWZvcmUgdG9kYXkpLgoKWzFdICIvY2x1c3Rlci90dWZ0cy9ocGMvdG9vbHMvUi80LjAuMCIKWzJdICIvY2x1c3Rlci9ob21lL2FyaG9kZTA1L1IveDg2XzY0LXBjLWxpbnV4LWdudS1saWJyYXJ5LzQuMCIKWzNdICIvb3B0L3NoYXJlZC9SLzQuMC4wL2xpYjY0L1IvbGlicmFyeSIgCgoKQ29tbWFuZHMgdG8gc3BlY2lmeSB0aGUgc2hhcmVkIGRpcmVjdG9yeSBhcyB0aGUgZmlyc3QgcGxhY2UgdG8gbG9vayBmb3IgUiBsaWJyYXJpZXMgYW5kIGNoZWNrIHRoZSBvdXRwdXQuCgpgYGB7ciBjaGVjayBsaWJyYXJ5IHBhdGhzfQoKLmxpYlBhdGhzKGMoJy9jbHVzdGVyL3R1ZnRzL2hwYy90b29scy9SLzQuMC4wJywubGliUGF0aHMoKSkpCgoubGliUGF0aHMoKQoKYGBgCgoKIyMjIE1vZHVsZXMgYW5kIENvbmRhIEVudmlyb25tZW50cwoKSW4gdGhpcyB3b3Jrc2hvcCwgd2Ugd2lsbCBzb21ldGltZXMgYmUgbG9hZGluZyBtb2R1bGVzIGZyb20gdGhlIEhQQyB0byB1c2UgaW4gYSBjb2RlIGNodW5rLgoKSGVyZSBpcyBhbiBleGFtcGxlIGNvZGUgY2h1bmsgdGhhdCBsb2FkcyBhIG1vZHVsZSBmb3Igc2FtdG9vbHMgYW5kIHJ1bnMgdGhlIGNvbW1hbmQgd2l0aCB0aGUgaGVscCBmbGFnIHRvIGdlbmVyYXRlIHNvbWUgb3V0cHV0IHRvIHRlc3QgdGhhdCB0aGUgbW9kdWxlIGxvYWRlZCBjb3JyZWN0bHkuCgpJZiB0aGUgYmFzaCBlbnZpcm9ubWVudCBpcyBub3QgZGVzaWduYXRlZCBpbiB0aGUgc2V0dXAgY2h1bmssIHlvdSBtYXkgbmVlZCB0byBhZGQgdGhpcyBiYXNoIGNvbW1hbmQgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgY2h1bmsgdG8gZW5hYmxlIG1vZHVsZSBsb2FkaW5nLiAKCmBzb3VyY2Ugfi8uYmFzaHJjYAoKYGBge2Jhc2ggZXhhbXBsZSBtb2R1bGUgY29tbWFuZCwgcmVzdWx0cz0naGlkZSd9Cgptb2R1bGUgbG9hZCBzYW10b29scy8xLjkKc2FtdG9vbHMgLS1oZWxwCgpgYGAKCgpUaGUgYmVoYXZpb3Igb2YgbW9kdWxlcyBpbiB0aGUgY29kZSBjaHVua3MgZGlmZmVycyBmcm9tIG91ciBkaXJlY3QgY29tbWFuZCBsaW5lLgoKVGhlIFJtYXJrZG93biBub3RlYm9vayB3aWxsIG5vdCByZW1lbWJlciBpdCBmcm9tIGNodW5rIHRvIGNodW5rLiBTbyBsb2FkIHRoZSBtb2R1bGVzIGluIHRoZSBjaHVua3Mgd2hlcmUgdGhlIGNvbW1hbmRzIGFyZSBuZWVkZWQuCgpBbiBleGFtcGxlIHdpdGggY29uZGEgZW52aXJvbm1lbnRzIHdpbGwgYmUgc2hvd24gaW4gUGFydCBJSS4KCi0tLQoKIyMjIyMgV2hhdCBoYXBwZW5zIHdoZW4geW91IHJ1biB0aGlzIGNodW5rPwoKYGBge2Jhc2h9Cgptb2R1bGUgbGlzdAoKYGBgCgotLS0KCiMjIyMjIFdoeSB1c2UgbW9kdWxlcyBpbnN0ZWFkIG9mIGNvbmRhIGVudmlyb25tZW50cz8KCiogICBDb25kYSBlbnZpcm9ubWVudHMgYXJlIGdyZWF0IGZvciBpbnN0YWxsaW5nIHNwZWNpZmljIHZlcnNpb25zIG9mIHByb2dyYW1zLCBidXQgb2Z0ZW4gYnJpbmcgaW4gY2xhc2hpbmcgZGVwZW5kZW5jaWVzLCBhbmQgb25seSBvbmUgaXMgYWN0aXZlIGF0IGEgdGltZS4KCiogICBVc2luZyBIUEMgbW9kdWxlcyBjYW4gcHJvdmlkZSBtb3JlIGludGVncmF0aW9uIGJlY2F1c2UgeW91IGNhbiBsb2FkIHNldmVyYWwgYXQgb25lIHRpbWUuCgoqICAgT2YgY291cnNlLCBjb25kYSBlbnZpcm9ubWVudHMgY291bGQgYmUgdXNlZCBpZiB5b3UgbG9hZCBhbGwgdGhlIHJlcXVpcmVkIHByb2dyYW1zIGludG8gdGhlIHNhbWUgZW52aXJvbm1lbnQuIFdlIHdpbGwgc2VlIGFuIGV4YW1wbGUgb2YgdGhpcyBsYXRlciB3aXRoIE1ldGF3cmFwCgoKIyMgSW50cm9kdWNpbmcgdGhlIERhdGEgLSBHaWFudCBQYW5kYSB0aWNrcwoKVGlja3MgYXJlIGNhcGFibGUgb2Ygc3ByZWFkaW5nIHBhdGhvZ2VucyAodmlydXNlcywgYmFjdGVyaWEgYW5kIG90aGVyIHBhcmFzaXRlcykgYW1vbmcgYSBob3N0IHBvcHVsYXRpb24uIE5vdCBtdWNoIGlzIGtub3duIGFib3V0IHRoZSBzcHJlYWQgb2YgdGljay1ib3JuZSB2aXJ1c2VzIGluIEdpYW50IFBhbmRhcy4gVGhlIGRlbnNpdHkgb2YgZ2lhbnQgcGFuZGFzIGluIGJyZWVkaW5nIGNhcHRpdml0eSBpbiBTaWNodWFuIFByb3ZpbmNlLCBDaGluYSBtYXkgbGVhZCB0byBtb3JlIHRyYW5zbWlzc2lvbiBvZiB0aGVzZSBkaXNlYXNlcy4gVGhlIHJlc2VhcmNoZXJzIHdobyBsb2FkZWQgdGhpcyBkYXRhIGludG8gdGhlIFNSQSB3ZXJlIGludGVyZXN0ZWQgaW4gY2hhcmFjdGVyaXppbmcgdGhlIHZpcm9tZSBvZiB0aGVzZSB0aWNrcyBhbmQgdG8gY29tcGFyZSB0aGVzZSB3aXRoIHRoZSB2aXJvbWUgb2YgdGhlIHBhbmRhcy4KCldlIGFyZSBub3QgZ29pbmcgdG8gcmVzdHJpY3Qgb3VyIGFuYWx5c2lzIHRvIHRoZSB2aXJvbWUsIGFuZCBqdXN0IHRha2UgYSBnZW5lcmFsIGxvb2sgYXQgd2hhdCB0aGVzZSB0aWNrcyBhcmUgY2FycnluZyBhcm91bmQgaW4gZ2VuZXJhbCB1c2luZyBwcmFjdGljYWwgbWV0YWdlbm9taWNzIHdvcmtmbG93cy4KCltDaGVjayBvdXQgdGhlIGJpb3Byb2plY3QgaGVyZV0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9iaW9wcm9qZWN0L1BSSk5BODA4NzkzKSAKCltDaGVjayBvdXQgdGhlIGZpbmFsIHBhcGVyIGhlcmVdKGh0dHBzOi8vam91cm5hbHMuYXNtLm9yZy9kb2kvMTAuMTEyOC9zcGVjdHJ1bS4wMjAzNC0yMikKCgohW0lzIGhlIHNsZWVweSBvciBpcyBoZSBzaWNrPyBcbGFiZWx7R2lhbnQgUGFuZGEgfV0oLi9pbWFnZXMvc2xlZXB5X3BhbmRhLnBuZyl7d2lkdGg9NTAlfQoKCldlIGFyZSBnb2luZyB0byBicmluZyBpbiBzb21lIG9mIHRoZSBkYXRhIGZyb20gdGhpcyBiaW9wcm9qZWN0IHRvIG91ciBNZXRhZ2Vub21pY3MgVHV0b3JpYWwgc3BhY2UuCgojIyMjIFdoYXQgaW5mb3JtYXRpb24gY2FuIHdlIGZpbmQgaW4gdGhlIG1ldGFkYXRhPwoKU1JBIE1ldGFkYXRhIC0gZXZlcnkgcHJvamVjdCBpcyBkaWZmZXJlbnQhCgpFeGFtcGxlIGZyb20gQmlvUHJvamVjdCBbTWljcm9iZXMgRnJvbSBNdW1dKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvVHJhY2VzL3N0dWR5Lz9xdWVyeV9rZXk9MTEmV2ViRW52PU1DSURfNjM2YjZmNTU1ZTM0NjE3Yzg1NzZkYjhmJm89YWNjX3MlM0FhKQoKCiFbTXVtIHNwb25nZSBtZXRhZGF0YSBcbGFiZWx7VGljayBNZXRhZGF0YSB9XSguL2ltYWdlcy9tdW1fbWV0YWRhdGEucG5nKXt3aWR0aD03MCV9CgoKCltUaGUgTWV0YWRhdGEgZnJvbSBvdXIgQmlvUHJvamVjdF0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9UcmFjZXMvc3R1ZHkvP3F1ZXJ5X2tleT0xNSZXZWJFbnY9TUNJRF82MzZiNmY1NTVlMzQ2MTdjODU3NmRiOGYmbz1hY2NfcyUzQWEpCgoKIVtQYW5kYSB0aWNrIG1ldGFkYXRhIFxsYWJlbHtUaWNrIE1ldGFkYXRhIH1dKC4vaW1hZ2VzL3RpY2tfbWV0YWRhdGEucG5nKXt3aWR0aD03MCV9CgojIyMjIyBRdWVzdGlvbiAtIFdoeSBkbyBtb3N0IG9mIHRoZSByZWFkcyBvZiAic3BvdCBsZW5ndGgiIGVxdWFsIHRvIDUwMj8KClNvbWV0aGluZyB5b3UgbWF5IGhhdmUgbm90aWNlZCBpcyB0aGF0IHRoZSByZWFkcyBhcmUgc3VzcGljaWFsbHkgZXZlbiBpbiBudW1iZXIsIGF0IGxlbmd0aCA1MDIuIFRoZSBleHBlcmltZW50YWwgZGVzaWduIHN0YXRlcyB0aGF0IHRoZSByZWFkcyB3ZXJlIHBhaXJlZC1lbmQgMngyNTAuCgoKIyMjIyMgUXVlc3Rpb24gLSBXaG8gaXMgcmVzcG9uc2libGUgZm9yIGxvYWRpbmcgQmlvUHJvamVjdCBtZXRhZGF0YSB0byB0aGUgTkNCST8KCgojIyMgT2J0YWluaW5nIERhdGEgZnJvbSBTUkEKClRoZSBkYXRhIHdlIGFyZSBnb2luZyB0byBjb3B5IG92ZXIgY2FuIGJlIG9idGFpbmVkIGRpcmVjdGx5IGZyb20gdGhlIFNSQSBieSB1c2luZyBvdXIgY29tbWFuZCBsaW5lIG1vZHVsZSBmb3IgdGhlIFNSQVRvb2xraXQuIFRoaXMgY2FuIHRha2UgYSBsaXR0bGUgd2hpbGUsIGRlcGVuZGluZyBvbiB0aGUgaW50ZXJuZXQgY29ubmVjdGlvbiBhbmQgd2hpY2ggc291cmNlIHRoZSBmaWxlcyBhcmUgcHVsbGVkIGZyb20gKG9uLXByZW0sIEFXUyBvciBHQ1ApLgoKCiMjIyMgIlNwb3RzIiBpbiBTUkEgYXJlIG5vdCB0aGUgc2FtZSBhcyAicmVhZHMiCgoqIEEgc3BvdCBpcyBhbGwgdGhlIGluZm8geW91IGdvdCBmcm9tIG9uZSAic3BvdCIgb24gdGhlIGZsb3cgY2VsbC4KKiBZb3UgZ2V0IDQgcmVhZHMgcGVyIHNwb3Qgd2l0aCB0b2RheSdzIGlsbHVtaW5hIHNlcXVlbmNpbmc6IGZvcndhcmQgYmFyY29kZSwgZm9yd2FyZCByZWFkLCByZXZlcnNlIGJhcmNvZGUsIHJldmVyc2UgcmVhZC4gCgohW05DQkkgU1JBICJTcG90cyIgXGxhYmVse1Nwb3RzIGZyb20gU1JBIH1dKC4vaW1hZ2VzL3NwbGl0LTMucG5nKXt3aWR0aD03MCV9CgoKIyMjIyBQcmFjdGljZSBkb3dubG9hZGluZyBkYXRhIGZyb20gU1JBCgoKYGBge2Jhc2h9Cgptb2R1bGUgbG9hZCAvY2x1c3Rlci90dWZ0cy9iaW8vdG9vbHMvbW9kdWxlX2ZpbGVzL3NyYS8zLjAuMApta2RpciAtcCB0ZXN0X1NSQQpmYXN0cS1kdW1wIC0tb3V0ZGlyIHRlc3RfU1JBIC1YIDUwMCAtLXNraXAtdGVjaG5pY2FsIC0tcmVhZC1maWx0ZXIgcGFzcyAtLXJlYWRpZHMgLS1taW5SZWFkTGVuIDIwMCAtLXNwbGl0LWUgU1JSMTgwODYzNjQKCmBgYAoKKipDb21tYW5kIExpbmUgUGFyYW1ldGVycyoqCgoqIEdyYXAgZmlyc3QgbWlsbGlvbiBsaW5lcyBgLVggNTAwYAoqIE9ubHkgImJpb2xvZ2ljYWwgcmVhZHMiIGAtLXNraXAtdGVjaG5pY2FsYAoqIFJlbW92ZSByZWFkcyB0aGF0IGFyZSBtb3N0bHkgTidzICBgLS1yZWFkLWZpbHRlciBwYXNzYAoqIEFwcGVuZCBgLjFgIHRvIGZvcndhcmQgcmVhZCBoZWFkZXIgYC4yYCB0byByZXZlcnNlIHJlYWQgaGVhZGVyICAtLXJlYWRpZHMKKiBLZWVwIG1hdGVkIHBhaXJzIGFuZCBzaW5nbGV0b25zLCB1c2UgLeKAk3NwbGl0LWUgYW5kIGEgdGhyZWUgZmlsZXMgd2lsbCBiZSBnZW5lcmF0ZWQgaWYgb3JwaGFucyBhcmUgcHJlc2VudCAoZm9yd2FyZCwgcmV2ZXJzZSwgYW5kIHVubWF0Y2hlZCBtYXRlcykKCgpUaGVyZSBzaG91bGQgYmUgdGhyZWUgbmV3IGZpbGVzIGluIHlvdXIgYE1ldGFnZW5vbWljczIwMjIvdGVzdF9TUkFgIGRpcmVjdG9yeS4KClRoZSBvdXRwdXQgaXMgc21hbGwgZW5vdWdoIHRoYXQgd2UgY2FuIGxvb2sgaW50byB0aGUgZmFzdHEgZmlsZSBieSBjbGlja2luZyBvbiBpdC4KCiogQ29uZmlybSB0aGUgYC4xYCBhbmQgYC4yYCB3ZXJlIGFwcGVuZGVkIHRvIHlvdXIgZm9yd2FyZCByZWFkIGhlYWRlcnMgYW5kIHJldmVyc2UgcmVhZCBoZWFkZXJzCiogV2hhdCBoYXBwZW5lZCBpbnNpZGUgdGhlIHNpbmdsZXRvbiBmaWxlPyBEbyB5b3Ugc2VlIGAuMWAsIGAuMmAgb3IgYm90aD8KKiBRQyBCZXN0IHByYWN0aWNlOiBDb3VudCB0aGUgbnVtYmVyIG9mIGxpbmVzIGluIHRoZSBvdXRwdXQgZmlsZXMKCmBgYHtiYXNofQoKd2MgLWwgLi90ZXN0X1NSQS8qLmZhc3RxCgpgYGAKKiBIb3cgbWFueSBsaW5lcyBhcmUgaW4gb3VyIGZhc3RxIG91dHB1dCBmaWxlcyBhbmQgd2h5PyAKCiAgKEhpbnQgMTogd2UgYXNrZWQgZm9yIDUwMCAic3BvdHMiLCBub3QgcmVhZHMpCiAgKEhpbnQgMjogaG93IGRpZCBvdXIgcGFyYW1ldGVyIGNob2ljZXMgYWZmZWN0IG91ciBvdXRwdXRzPykKCgojIyMjIyBBIE5vdGUgYWJvdXQgRmFzdGVycS1kdW1wCgpJbiBzb21lIGNhc2VzLCB0aGUgbmV3ZXIgdmVyc2lvbiBvZiB0aGlzIHRvb2wgYGZhc3RlcnEtZHVtcGAgd2lsbCBhdXRvbWF0aWNhbGx5IHJ1biB0aGUgc3BsaXQtZSB2ZXJzaW9uIG9mIHRoZSBjb21tYW5kIHdpdGhvdXQgYWRkaW5nIHRoaXMgcGFyYW1ldGVyLiBJdCBpcyB3b3J0aCBsb29raW5nIGF0IHRoZSBvcHRpb25zIGJlZm9yZSB1c2luZyBpdCwgYmVjYXVzZSBzb21lIG9mIHRoZSBwYXJhbWV0ZXIgbWVhbmluZ3MgaGF2ZSBjaGFuZ2VkLgoKClRoZSBmb2xsb3dpbmcgY29kZWJsb2NrIGlzIGZvciByZWZlcmVuY2UsIHRvIHVzZSB0aGUgY2h1bmssIHJlbW92ZSB0aGUgYCNgIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIGxpbmUuCgoKYGBge2Jhc2gsIGluY2x1ZGUgPSBGQUxTRX0KCiNzb3VyY2Ugfi8uYmFzaHJjCiNtb2R1bGUgbG9hZCAvY2x1c3Rlci90dWZ0cy9iaW8vdG9vbHMvbW9kdWxlX2ZpbGVzL3NyYS8zLjAuMAoKI2Zhc3RxLWR1bXAgLVggMTAwMDAwMCAtLXNraXAtdGVjaG5pY2FsIC0tY2xpcCAtLXJlYWQtZmlsdGVyIHBhc3MgLS1zcGxpdC1zcG90IC0tcmVhZGlkcyAtLW1pblJlYWRMZW4gMjAwIC0tc3BsaXQtZSBTUlIxODA4NTY5MQoKI2Zhc3RxLWR1bXAgLVggMTAwMDAwMCAtLXNraXAtdGVjaG5pY2FsIC0tY2xpcCAtLXJlYWQtZmlsdGVyIHBhc3MgLS1zcGxpdC1zcG90IC0tcmVhZGlkcyAtLW1pblJlYWRMZW4gMjAwIC0tc3BsaXQtZSBTUlIxODA4NTcwOAoKI2Zhc3RxLWR1bXAgLVggMTAwMDAwMCAtLXNraXAtdGVjaG5pY2FsIC0tY2xpcCAtLXJlYWQtZmlsdGVyIHBhc3MgLS1zcGxpdC1zcG90IC0tcmVhZGlkcyAtLW1pblJlYWRMZW4gMjAwIC0tc3BsaXQtZSBTUlIxODA4NjI3NwoKI2Zhc3RxLWR1bXAgLVggMTAwMDAwMCAtLXNraXAtdGVjaG5pY2FsIC0tY2xpcCAtLXJlYWQtZmlsdGVyIHBhc3MgLS1zcGxpdC1zcG90IC0tcmVhZGlkcyAtLW1pblJlYWRMZW4gMjAwIC0tc3BsaXQtZSBTUlIxODA4NjM0MgoKI2Zhc3RxLWR1bXAgLVggMTAwMDAwMCAtLXNraXAtdGVjaG5pY2FsIC0tY2xpcCAtLXJlYWQtZmlsdGVyIHBhc3MgLS1zcGxpdC1zcG90IC0tcmVhZGlkcyAtLW1pblJlYWRMZW4gMjAwIC0tc3BsaXQtZSBTUlIxODA4NjM2NAoKI2Zhc3RxLWR1bXAgLVggMTAwMDAwMCAtLXNraXAtdGVjaG5pY2FsIC0tY2xpcCAtLXJlYWQtZmlsdGVyIHBhc3MgLS1zcGxpdC1zcG90IC0tcmVhZGlkcyAtLW1pblJlYWRMZW4gMjAwIC0tc3BsaXQtZSBTUlIxODA4NjU3NQoKI2Zhc3RxLWR1bXAgLVggMTAwMDAwMCAtLXNraXAtdGVjaG5pY2FsIC0tY2xpcCAtLXJlYWQtZmlsdGVyIHBhc3MgLS1zcGxpdC1zcG90IC0tcmVhZGlkcyAtLW1pblJlYWRMZW4gMjAwIC0tc3BsaXQtZSBTUlIxODA5MTMxNgoKI2Zhc3RxLWR1bXAgLVggMTAwMDAwMCAtLXNraXAtdGVjaG5pY2FsIC0tY2xpcCAtLXJlYWQtZmlsdGVyIHBhc3MgLS1zcGxpdC1zcG90IC0tcmVhZGlkcyAtLW1pblJlYWRMZW4gMjAwIC0tc3BsaXQtZSBTUlIxODA5MTczNwoKYGBgCgoKCgojIyMjICAKCmBgYHtiYXNoIHF1YWxpdHkgY2hlY2sgb2YgdGhlIHJhdyBmaWxlc30KCiMvY2x1c3Rlci90dWZ0cy9ocGMvdG9vbHMvc3BhY2svbGludXgtcmhlbDctaXZ5YnJpZGdlL2djYy05LjMuMC9mYXN0cWMtMC4xMS45LWVlaWo1andud2F1M3R0eDRtNTNieGFmbXhiaG00Zmp6L2Jpbi9mYXN0cWMgLi9NR0RhdGEvKm92ZXJyZXAuZmFzdHEKCnNvdXJjZSB+Ly5iYXNocmMKbW9kdWxlIGxvYWQgZmFzdHFjCm1rZGlyIC1wIGZhc3RxYwpmYXN0cWMgLi9kYXRhLypwYXNzKi5mYXN0cSAtbyBmYXN0cWMKCmBgYAoKYGBge2Jhc2ggYWdncmVnYXRlIHRoZSByYXcgcXVhbGl0eSBjaGVja30KCiNzb3VyY2Ugfi8uYmFzaHJjCm1vZHVsZSBsb2FkIG11bHRpcWMvMS43LjAKbWtkaXIgLXAgbXVsdGlxYwptdWx0aXFjIC4vZmFzdHFjIC1vIC4vbXVsdGlxYwoKYGBgCgpDaGVjayB0aGUgcXVhbGl0eSBvZiB5b3VyIHJlc3VsdHMgYnkgbmF2aWdhdGluZyB0byB0aGUgZmlsZSBmb2xkZXIgZm9yIG11bHRpcWMgYW5kIGNsaWNraW5nIG9uIHRoZSBodG1sIGZpbGVzIHRoYXQgd2VyZSBnZW5lcmF0ZWQuCgpPa2F5LCBzbyB0aGUgZGF0YSBpcyBub3QgdGhlIG1vc3QgcGVyZmVjdCwgYnV0IHdlIGp1c3QgbmVlZCBhIHNldCB0aGF0IGNhbiBtYWtlIGl0IHRocm91Z2ggdGhlIGFuYWx5c2lzLgoKIyMgUHJlcHJvY2Vzc2luZyBSZWFkcwoKTWV0YWdlbm9taWNzIGhhcyBiZW5lZml0ZWQgZnJvbSBrLW1lciBiYXNlZCBhcHByb2FjaGVzLgoKfHx8fCBBZGQgZGVzY3JpcHRpb2luIG9mIGstbWVyIGJhc2VkIGFwcHJvYWNoZXMgaGVyZSB8fHx8CgpCQ0JpbyB0b29scyBhcmUgdXNlZnVsIGZvciBjbGVhaW5pbmcgbWV0YWdlbm9taWNzIGZpbGVzLCBiZWNhdXNlIG1hbnkgc2ltcGxlIGZ1bmN0aW9ucyBjYW4gYmUgY2FsbGVkIGFuZCBzcGVkIHVwIHVzaW5nIGttZXJzLgoKRm9yIGV4YW1wbGUsIGxldCdzIHJlbW92ZSBrbm93biBhZGFwdGVyIGFuZCBvdGhlciBjb250YW1pbmF0aW9uIHVzaW5nIHRoZSBOQ0JJIGRhdGFiYXNlIGNhbGxlZCAiVW5pVmVjIgoKfHx8fHwgQWRkaW5nIG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgVW5pVmVjIGhlcmUgfHx8fHx8fAoKCgpgYGB7YmFzaCBsb29rIGF0IFVuaVZlYy5mYXN0YX0KCmNkIH4vTWV0YWdlbm9taWNzMjAyMgojcHdkCgojZ3JlcCAiVHJ1U2VxIiAuL2RhdGEvVW5pVmVjLmZhc3RhCgpncmVwICJQQ1IgUHJpbWVyIEluZGV4IDkiIC4vZGF0YS9VbmlWZWMuZmFzdGEKCgoKYGBgCgoKIyMjIFJlbW92ZSBjb250YW1pbmF0aW9uIGZyb20gc2VxdWVuY2VzIHdpdGggQkNCaW8gdG9vbHMKCkFyZSB0aGVzZSByZXBlYXRzIGJpb2xvZ2ljYWwgKHBhcnQgb2YgdGhlIGdlbm9tZSkgb3IgdGVjaG5pY2FsIChwcmltZXIgYW1wbGlmaWNhdGlvbiwgdW5kZXJhYnVuZGFuY2Ugb2Ygc2FtcGxlIG9yIGxhY2sgb2YgUGhpWCBzcGlrZS1pbik/IFdoYXQgZG9lcyB0aGUgcmF3IHNlcXVlbmNpbmcgZGF0YSBzaG93IHVzPwoKCkhlcmUgaXMgYW4gZXhhbXBsZSBvZiBob3cgYmJkdWsuc2ggY2FuIGJlIHVzZWQgdG8gc2ltdWx0YW5lb3VzbHkgcmVtb3ZlIGFkYXB0ZXJzLCBwaGlYIHNwaWtlLWluIGFuZCBvdmVycmVwcmVzZW50ZWQgc2VxdWVuY2VzIGZyb20gb3VyIGN1c3RvbSBmaWxlLgoKYGBge2Jhc2ggcmVtb3ZlIHNlcXVlbmNlcyBvbiByYXcgZGF0YSBmaWxlfQoKI3NvdXJjZSB+Ly5iYXNocmMKbW9kdWxlIGxvYWQgamF2YS8xLjguMF82MAptb2R1bGUgbG9hZCAvY2x1c3Rlci90dWZ0cy9iaW8vdG9vbHMvbW9kdWxlX2ZpbGVzL2JjYmlvLzEuMS41Cm1rZGlyIC1wIGRlY29uCgoKYmJkdWsuc2ggLVhteDEwZyAtdGJvICAtdHBlIFwKaW4xPWRhdGEvU1JSMTgwODU2OTFfcGFzc18xLmZhc3RxIFwKaW4yPWRhdGEvU1JSMTgwODU2OTFfcGFzc18yLmZhc3RxIFwKb3V0MT1kZWNvbi9TUlIxODA4NTY5MV9kZWNvbl8xLmZhc3RxIFwKb3V0Mj1kZWNvbi9TUlIxODA4NTY5MV9kZWNvbl8yLmZhc3RxIFwKb3V0cz1kZWNvbi9TUlIxODA4NTY5MV9kZWNvbl9zaW5nLmZhc3RxIFwKcmVmPWNvbnRhbWluYW50cy9VbmlWZWMuZmFzdGEgXApyZWY9Y29udGFtaW5hbnRzL292ZXJyZXAuZmFzdGEgXApyZWY9cGhpeCBcCnJlZj1hZHBhdGVycyBcCmt0cmltPXIgaz0yMSByY29tcD10IG1pbms9MTEgaGRpc3Q9MiBtaW5sZW49MjAwIFwKCgpgYGAKCiMjIyMgV2hpbGUgdGhlIG5leHQgY2h1bmsgaXMgcnVubmluZywgbGV0J3MgdGFsayBhYm91dCBrbWVyLWJhc2VkIGFwcHJvYWNoZXMgdG8gZmlsdGVyaW5nLgoKW0JCRFVLID0gRGVjb250YW1pbmF0aW9uIFVzaW5nIEttZXJzXShodHRwczovL2pnaS5kb2UuZ292L2RhdGEtYW5kLXRvb2xzL3NvZnR3YXJlLXRvb2xzL2JidG9vbHMvYmItdG9vbHMtdXNlci1ndWlkZS9iYmR1ay1ndWlkZS8pCgoqIGAtdGJvYCB0cmltcyBvdmVybGFwcGluZyBiYXNlcyBpbiBwYWlyZWQgZW5kIHJlYWRzCiogYC10cGVgIHRyaW1zIGJvdGggcGFpcmVkIGVuZCByZWFkcyB0byB0aGUgc2FtZSBsZW5ndGgKKiBgLWluMWAsYC1pbjJgLGBvdXQxYCxgb3V0MmAsYG91dHNgIG1lYW5zIGlucHV0IGZvcndhcmQgYW5kIHJldmVyc2UgcmVhZHMgYW5kIG91dHB1dCBmb3J3YXJkIGFuZCByZXZlcnNlIHBsdXMgb3JwaGFuZWQgcmVhZHMKKiBgcmVmYCBjYW4gYmUgYW55IGZpbGUgaW4gZmFzdGEgZm9ybWF0IG9yIGJha2VkLWluIG9wdGlvbnMgc3VjaCBhcyBgcGhpWGAgYW5kIGBhZGFwdGVyc2AKKiBgcmVmYCBjYW4gYmUgcmVwbGFjZWQgd2l0aCBgbGl0ZXJhbD1BQ1RHR1QsVFRUR0dUR2Agd2l0aCBhbnkgbGlzdCBvZiBzdHJpbmdzCiogYGt0cmltPXJgIG1lYW5zIHRvIHRyaW0gZnJvbSBgMy1wcmltZWAgZW5kCiogYGtgIHJlZmVycyB0byB0aGUgYGttZXJgIHNpemUgdGhhdCBpcyBjaG9zZW4KKiBgbWlua2AgYWxsb3dzIGEgc2hvcnRlciBga21lcmAgc2l6ZSBhdCB0aGUgZW5kIG9mIHRoZSBzZXF1ZW5jZQoqIGBoZGlzdGAgcmVmZXJzIHRvIGhhbW1pbmcgZGlzdGFuY2UgLSBudW1iZXIgb2YgbWlzbWF0Y2hlcyBhbGxvd2VkIGluIGEga21lcgoqIGBtaW5sZW5gIGluZGljYXRlcyB0aGUgbWluaW11bSBsZW5ndGggb2YgdGhlIHNlcXVlbmNlIHRvIGtlZXAgYWZ0ZXIgdHJpbW1pbmcKCgoKYGBge2Jhc2ggcmVtb3ZlIHNlcXVlbmNlcyBvbiBhbGwgcmF3IGRhdGEgZmlsZXN9Cgojc291cmNlIH4vLmJhc2hyYwptb2R1bGUgbG9hZCBqYXZhLzEuOC4wXzYwCm1vZHVsZSBsb2FkIC9jbHVzdGVyL3R1ZnRzL2Jpby90b29scy9tb2R1bGVfZmlsZXMvYmNiaW8vMS4xLjUKbWtkaXIgLXAgZGVjb24KCgpscyBkYXRhLypfcGFzc18xLmZhc3RxIHwgd2hpbGUgcmVhZCBsaW5lIDsgZG8gXAoKYmJkdWsuc2ggLVhteDEwZyAtdGJvIC10cGUgXAppbjE9JGxpbmUgXAppbjI9ZGF0YS8kKGJhc2VuYW1lICRsaW5lIF9wYXNzXzEuZmFzdHEpX3Bhc3NfMi5mYXN0cSBcCm91dDE9ZGVjb24vJChiYXNlbmFtZSAkbGluZSBfcGFzc18xLmZhc3RxKV9kZWNvbl8xLmZhc3RxIFwKb3V0Mj1kZWNvbi8kKGJhc2VuYW1lICRsaW5lIF9wYXNzXzEuZmFzdHEpX2RlY29uXzIuZmFzdHFcIFwKb3V0cz1kZWNvbi8kKGJhc2VuYW1lICRsaW5lIF9wYXNzXzEuZmFzdHEpX2RlY29uX3NpbmcuZmFzdHEgXApyZWY9Y29udGFtaW5hbnRzL1VuaVZlYy5mYXN0YSBcCnJlZj1jb250YW1pbmFudHMvb3ZlcnJlcC5mYXN0YSBcCnJlZj1waGl4IFwKcmVmPWFkYXB0ZXJzIFwKa3RyaW09ciBrPTIxIHJjb21wPXQgbWluaz0xMSBoZGlzdD0yIG1pbmxlbj0yMDA7IFwKZG9uZQoKCgoKYGBgCgoKCgoKCgpgYGB7YmFzaCBxdWFsaXR5IGNoZWNrIGRlY29uIGZpbGVzfQojc291cmNlIH4vLmJhc2hyYwptb2R1bGUgbG9hZCBmYXN0cWMKbWtkaXIgLXAgZmFzdHFjX2RlY29uCmZhc3RxYyAuL2RlY29uLypkZWNvbiouZmFzdHEgLW8gZmFzdHFjX2RlY29uCgpgYGAKCgoKCgoKYGBge2Jhc2ggYWdncmVnYXRlIHRoZSBkZWNvbiBxdWFsaXR5IGNoZWNrfQoKI3NvdXJjZSB+Ly5iYXNocmMKbW9kdWxlIGxvYWQgbXVsdGlxYy8xLjcuMApta2RpciAtcCBtdWx0aXFjX2RlY29uCm11bHRpcWMgLi9mYXN0cWNfZGVjb24gLW8gLi9tdWx0aXFjX2RlY29uCgpgYGAKCgoKIyMjIyBRdWVzdGlvbjogRGlkIHdlIGdldCByaWQgb2YgYWxsIHRoZSBhZGFwdGVyIHNlcXVlbmNlcz8gV2hhdCB3b3VsZCB5b3VyIG5leHQgc3RlcCBiZT8KCgojIyMjIFF1ZXN0aW9uOiBJcyB0aGVyZSBhIHBhcnRpY3VsYXIgdGljayBwb29sIHRoYXQgd2UgbWF5IHdhbnQgdG8gcmVtb3ZlIGJlZm9yZSBhc3NlbWJseT8KClRvIGJlIHJlbW92ZWQgYmVmb3JlIGFzc2VtYmx5OgoKKiBJZ25vcmUgc2luZ2xlIHJlYWRzCiogSWdub3JlIGxvdyBjb3VudCByZWFkcyAoU1JSMTgwODYzNjQpCiogSWdub3JlIGxvdyBxdWFsaXR5IHJlYWRzIChTUlIxODA5MTczNyxTUlIxODA4NjI3NykKCgpgYGB7YmFzaCBrZWVwIHRoZSBnb29kIHRpY2tzfQoKbWtkaXIgLXAgZ29vZGRhdGEKCmVjaG8gU1JSMTgwODU2OTEgPiBnb29kZGF0YS50eHQKZWNobyBTUlIxODA4NTcwOCA+PiBnb29kZGF0YS50eHQKZWNobyBTUlIxODA4NjM0MiA+PiBnb29kZGF0YS50eHQKZWNobyBTUlIxODA4NjU3NSA+PiBnb29kZGF0YS50eHQKZWNobyBTUlIxODA5MTMxNiA+PiBnb29kZGF0YS50eHQKCgpjYXQgZ29vZGRhdGEudHh0IHwgd2hpbGUgcmVhZCAkbGluZTsgZG8gY3AgZGVjb24vJGxpbmUqMS5mYXN0cSBnb29kZGF0YTsgY3AgZGVjb24vJGxpbmUqMi5mYXN0cSBnb29kZGF0YTsgZG9uZQoKYGBgCgpUaGlzIGNvbmNsdWRlcyBQYXJ0IEksIHBsZWFzZSBjb21lIGJhY2sgYWZ0ZXIgdGhlIGJyZWFrIGZvciBQYXJ0IElJIC0gdXNpbmcgYSB3cmFwcGVyIHNjcmlwdCB0byBiaW4geW91ciBkYXRhLgoKCi0tLQoKIyMgUGFydCBJSQoKCiMjIyBSdW5uaW5nIGFuIEFzc2VtYmx5IG9uIHRoZSBDbGVhbmVkIERhdGEKCiMjIyMgVGhpcyBjb21tYW5kIHRha2VzIGFwcHJveGltYXRlbHkgMjAgbWludXRlcywgc28gdGhlIGNvbW1hbmRzIHVzZWQgdG8gbWFrZSB0aGUgYXNzZW1ibHkgYXJlIGNvbW1lbnRlZCBvdXQuCgoKYGBge2Jhc2ggcnVuIG1ldGFnZW5vbWUgYXNzZW1ibHl9CgoKIy9jbHVzdGVyL3R1ZnRzL2Jpby90b29scy9tZWdhaGl0LzEuMi45L2Jpbi9tZWdhaGl0ICAtbSAxNjAwMDAwMCAtdCAzMiAtLXJlYWQgLi9nb29kZGF0YS8qIFwKIy0tay1saXN0IDIxLDQxLDYxLDgxLDk5IFwKIy0tbm8tbWVyY3kgXAojLS1taW4tY291bnQgMiBcCiMtbyBtZWdhaGl0X291dC8KCmBgYAoKW01lZ2FoaXQ6IGRlIEJydWlqbiBncmFwaCBBc3NlbWJseV0oaHR0cHM6Ly9hY2FkZW1pYy5vdXAuY29tL2Jpb2luZm9ybWF0aWNzL2FydGljbGUvMzEvMTAvMTY3NC8xNzc4ODQpCgoKIVtNZWdhaGl0IHdvcmtmbG93IFxsYWJlbHtNZWdhaGl0IHdvcmtmbG93fV0oLi9pbWFnZXMvbWVnYWhpdF93b3JrZmxvdy5wbmcpe3dpZHRoPTMwJX0KCiMjIyMgV2hhdCBpcyBhIGRlQnJ1aWpuIGdyYXBoPwoKSXQgaXMgYW4gYXNzZW1ibHkgYWxnb3JpdGhtIHRoYXQgc3BsaXRzIHlvdXIgc2VxdWVuY2UgaW50byBrLW1lcnMgYW5kIHRyaWVzIHRvIGJ1aWxkIHRoZSBsb25nZXN0IGNvbnRpZ3MgYWxvbmcgdGhlIHNob3J0ZXN0IHBhcnNpbW9uaW91cyBwYXRoLgoKIVtNZWdhaGl0IHdvcmtmbG93IFxsYWJlbHtTb2huLCBqYW5nLWlsICYgTmFtLCBKaW4tV3UuICgyMDE2KS4gVGhlIHByZXNlbnQgYW5kIGZ1dHVyZSBvZiBkZSBub3ZvIHdob2xlLWdlbm9tZSBhc3NlbWJseS4gQnJpZWZpbmdzIGluIEJpb2luZm9ybWF0aWNzLiAxOS4gYmJ3MDk2LiAxMC4xMDkzL2JpYi9iYncwOTZ9XSguL2ltYWdlcy9kZUJydWlqbi5wbmcpCiAKCgoKVG8gc2F2ZSB0aW1lIGluIHRoZSB3b3Jrc2hvcCwgdGhlIGFzc2VtYmx5IGhhcyBiZWVuIGRvbmUgdXNpbmcgdGhlIGNvbW1lbnRlZCBvdXQgY29tbWFuZCBhYm92ZSBhbmQgcGxhY2VkIGludG8geW91ciB3b3Jrc2hvcCBmb2xkZXIgY2FsbGVkICJyZXBvcnRzIi4KCgojIyMgQ2hlY2tpbmcgdGhlIHF1YWxpdHkgb2Ygb3VyIEFzc2VtYmx5CgpbUXVhc3RdKGh0dHBzOi8vYWNhZGVtaWMub3VwLmNvbS9iaW9pbmZvcm1hdGljcy9hcnRpY2xlLzI5LzgvMTA3Mi8yMjg4MzIpIGlzIGEgY29tbW9ubHkgdXNlZCB0b29sIHRvIGFzc2VzcyBhc3NlbWJsaWVzLiBJdCB3aWxsIHByb3ZpZGUgYSByZXBvcnQgdGhhdCBpcyBlaXRoZXIgaW4gYSB0ZXh0IGZpbGUgb3IgYW4gaHRtbC4KCkxldCdzIHJ1biB0aGUgZm9sbG93aW5nIGNvbW1hbmQgYW5kIHRoZW4gbG9vayBmb3IgdGhlIHF1YXN0IHJlcG9ydCB0byBzZWUgaWYgd2UgaGF2ZSBhICJnb29kIiBhc3NlbWJseS4KCgpgYGB7YmFzaCBxdWFzdCBhbmFseXNpc30KCi9jbHVzdGVyL3R1ZnRzL2Jpby90b29scy9xdWFzdC81LjIuMC9xdWFzdC5weSAtbyBxdWFzdF9hc3NlbWJseSAuL3JlcG9ydHMvZmluYWwuY29udGlncy5mYQoKYGBgCgojIyMgVXNpbmcgS3Jha2VuIHRvIGNoZWNrIGZvciBNZXRhZ2Vub21lIENvbXBvc2l0aW9uCgpBdCB0aGlzIHBvaW50LCB3ZSBtYXkgYmUgaW50ZXJlc3RlZCBpbiB3aGV0aGVyIG91ciBhc3NlbWJseSBtYWtlcyBzZW5zZSBmb3Igb3VyIHNldCBvZiBjb250aWdzLgoKW0tyYWtlbjJdKGh0dHBzOi8vY2NiLmpodS5lZHUvc29mdHdhcmUva3Jha2VuMi8pIGlzIHRoZSBuZXdlc3QgdmVyc2lvbiBvZiBLcmFrZW4sIGEgdGF4b25vbWljIGNsYXNzaWZpY2F0aW9uIHN5c3RlbSB1c2luZyBleGFjdCBrLW1lciBtYXRjaGVzLiBUaGlzIGstbWVyIGJhc2VkIGFwcHJvYWNoIGhhcyB2ZXJ5IGZhc3QgY2xhc3NpZmljYXRpb24gc3BlZWRzIHdpdGggaGlnaCBhY2N1cmFjeS4KClRoaXMgYXBwcm9hY2ggZGlmZmVycyBmcm9tIGhvbW9sb2d5IGJhc2VkIGFwcHJvYWNoZXMgdGhhdCB0cnkgdG8gbWF0Y2ggc2VxdWVuY2VzIHRvIGVhY2ggb3RoZXIgYW5kIHNjb3JlIHRoZW0gYmFzZWQgb24gdGhlIG51bWJlciBvZiBtaXNtYXRjaGVzLCBkZWxldGlvbnMgYW5kIGluc2VydHMuIEtyYWtlbiB1c2VzIHRoZSBlbnRpcmUga21lciBjb21wb3NpdGlvbiBvZiB0aGUgY29udGlnIHRvIG1hdGNoIGl0IHRvIGEgZGF0YWJhc2Ugd2hlcmUgcmVmZXJlbmNlIHNlcXVlbmNlcyBoYXZlIGJlZW4gYnJva2VuIGRvd24gaW50byBrbWVyICJoYXNoZXMiIG9yIGEgZGF0YWJhc2Ugb2Ygd2hhdCB0aGUga21lcnMgbG9vayBsaWtlIGZvciBhIHBhcnRpY3VsYXIgb3JnYW5pc20uCgoKYGBge2Jhc2gga3Jha2VuIGNsYXNzaWZpY2F0aW9uIG9mIG91ciBhc3NlbWJseX0KCi9jbHVzdGVyL3R1ZnRzL2Jpby90b29scy9jb25kYV9lbnZzL2tyYWtlbi8yLjEuMi9iaW4va3Jha2VuMiAtLXVzZS1uYW1lcyAtLXRocmVhZHMgNCAtLWRiIC9jbHVzdGVyL3R1ZnRzL2Jpby90b29scy90cmFpbmluZy9tZXRhZ2Vub21pY3Mva3Jha2VuX3ZpcnVzIC0tcmVwb3J0IGtyYWtlbi5yZXBvcnQudHh0IC0tcXVpY2sgcmVwb3J0cy9maW5hbC5jb250aWdzLmZhIC0tY2xhc3NpZmllZC1vdXQgY2xhc3NpZmllZF9zZXF1ZW5jZXMudHN2ID4gc2VxdWVuY2VzLmtyYWtlbgoKCmBgYAoKV2UgY2FuIG9wZW4gdXAgdGhlIHNlcXVlbmNlIHJlcG9ydCBpbnNpZGUgUlN0dWRpbyBPbkRlbWFuZCBhbmQgc2Nyb2xsIHRocm91Z2ggdGhlIGZpbmRpbmdzLgoKVGhpcyBjYW4gYmUgYSB2ZXJ5IGxvbmcgbGlzdCBvZiBzcGVjaWVzIG5hbWVzLCBzbyBpdCBtYXkgYmUgbW9yZSBoZWxwZnVsIHRvIHVzZSBhbiBpbnRlcmFjdGl2ZSB2aXN1YWxpemF0aW9uIHRvb2wgdG8gbG9vayBhdCBvdXIgZGF0YS4KCgpbS3JvbmFdKGh0dHBzOi8vYm1jYmlvaW5mb3JtYXRpY3MuYmlvbWVkY2VudHJhbC5jb20vYXJ0aWNsZXMvMTAuMTE4Ni8xNDcxLTIxMDUtMTItMzg1KSBpcyBhIHZlcnkgdXNlZnVsIHRvb2wgdGhhdCBjYW4gdGFrZSBpbiBhIHZhcmlldHkgb2YgZm9ybWF0cy4gSW4gdGhpcyBjYXNlLCB3ZSBhcmUgcHJvdmlkaW5nIG91ciBrcmFrZW4ucmVwb3J0IHRvIHRoZSB2aXN1YWxpemF0aW9uLiBNZXRhYmFyY29kaW5nIGRhdGEgYXNzaWduZWQgdG8gYSB0YXhvbm9teSBjYW4gYWxzbyBiZSB1c2VkIGluIHRoaXMgY2FzZS4KCgpgYGB7YmFzaH0KCi9jbHVzdGVyL3R1ZnRzL2Jpby90b29scy9jb25kYV9lbnZzL2tyYWtlbi8yLjEuMi9iaW4va3RJbXBvcnRUYXhvbm9teSAtdCA1IC1tIDMgLW8ga3JvbmEuaHRtbCBrcmFrZW4ucmVwb3J0LnR4dAoKYGBgCgoKVGhlIG91dHB1dCwgd2hlbiBvcGVuZWQgaW4gYSB3ZWIgYnJvd3NlciwgYWxsb3dzIHRoZSB1c2VyIHRvIGludGVyYWN0IHdpdGggdGhlIGRhdGEgYW5kIGV4cGxvcmUgZGlmZmVyZW50IGxldmVscyBvZiB0aGUgZGF0YS4KCiFbS3JvbmEgb3V0cHV0IFxsYWJlbHtLcm9uYSBvdXRwdXR9XSguL2ltYWdlcy9rcm9uYV9leGFtcGxlLnBuZykKCgoKCiMjIyBXaGF0IGNhbiB3ZSBkbyB3aXRoIE1ldGFnZW5vbWljIEFwcHJvYWNoZXMKCiMjIyBDYXNlIFN0dWR5OiBEZXNjcmliaW5nIGEgQ29tcGxldGUgQ3lhbm9iYWN0ZXJpYWwgR2Vub21lIGFuZCBpdHMgU3ltYmlvbnRzIGZyb20gYW4gRXh0cmVtZWx5IEFyaWQgRW52aXJvbm1lbnQKCiMjIyMgVGhlIEF0YWNhbWEgRGVzZXJ0IC0gQXJlIHdlIG9uIE1hcnM/CgohW0F0YWNhbWEgRGVzZXJ0IFxsYWJlbHtBdGFjYW1hIERlc2VydCBFU08vUy4gTG93ZXJ5IC0gaHR0cHM6Ly93d3cuZXNvLm9yZy9wdWJsaWMvaW1hZ2VzL3BvdHcxNzE4YS99XSguL2ltYWdlcy9BdGFjYW1hLmpwZWcpCgoKClNvIHdlIGFyZSBwcm9iYWJseSBydW5uaW5nIG91dCBvZiB0aW1lIHRvIGNvbnRpbnVlIHdvcmtpbmcgaGFuZHMgb24uCgpMZXQncyB0YWtlIHNvbWUgdGltZSB0byBkaXNjdXNzIHdoYXQgdGhlIG5leHQgc3RlcHMgbWlnaHQgbG9vayBsaWtlLgoKVGhpcyBkaXNjdXNzaW9uIHdpbGwgY2VudGVyIGFyb3VuZCBhIHJlY2VudCBwcm9qZWN0IGZyb20gRHIuIFBlYXJzb24ncyBsYWIsIGNvbmR1Y3RlZCBieSBOZXZlZGEgTmF6LCBQaC5ELgoKTmV2ZWRhIGJ1aWxkcyBsaXR0bGUgcm9ib3RzIGFuZCBzZW5kcyB0aGVtIHRvIG91dGVyc3BhY2UuIChOZXZlZGEgaWYgeW91IGFyZSBoZXJlLCBmZWVsIGZyZWUgdG8gY29tbWVudCEpCgoKW1BsZWFzZSBvcGVuIHVwIHRoaXMgcGRmIGhlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS90dWZ0c2RhdGFsYWIvdHVmdHNXb3Jrc2hvcHMvYmxvYi9tYWluL2RvY3Mvb21pY3MvaW50cm8tbWV0YWdlbm9taWNzL01ldGFnZW5vbWljX3dvcmtmbG93X2V4YW1wbGUucGRmKSB0byBmaW5kIHRoZSBkaXNjdXNzaW9uLgoKCgojIyMjIEhlbHBmdWwgUmVzb3VyY2VzCgpBbHNvLCBmb3IgZnV0dXJlIHJlYWRpbmcsIEkgaGF2ZSBwbGFjZWQgdHdvIHVzZWZ1bCAucGRmJ3MgaW4gb3VyIHB1YmxpYyBnaXRodWIgcGFnZXMgdGhhdCBzdW1tYXJpemUgdGhlIHN0ZXBzIHdlIGFyZSBkaXNjdXNzaW5nIGluIGZ1cnRoZXIgZGV0YWlsLgoKW0Vzc2VudGlhbHMgaW4gTWV0YWdlbm9taWNzIEldKGh0dHBzOi8vZ2l0aHViLmNvbS90dWZ0c2RhdGFsYWIvdHVmdHNXb3Jrc2hvcHMvYmxvYi9tYWluL2RvY3Mvb21pY3MvaW50cm8tbWV0YWdlbm9taWNzL01ldGFnZW5vbWljc19Fc3NlbnRpYWxzXzEucGRmKQpbRXNzZW50aWFscyBpbiBNZXRhZ2Vub21pY3MgSUldKGh0dHBzOi8vZ2l0aHViLmNvbS90dWZ0c2RhdGFsYWIvdHVmdHNXb3Jrc2hvcHMvYmxvYi9tYWluL2RvY3Mvb21pY3MvaW50cm8tbWV0YWdlbm9taWNzL01ldGFnZW5vbWljc19Fc3NlbnRpYWxzXzIucGRmKQoKVGhpcyBtYXJrZG93biBhbmQgYXNzb2NpYXRlZCBmaWxlcyB3aWxsIGJlIHBsYWNlZCBpbiBvdXIgR2l0aHViIGFuZCBtYWlsZWQgb3V0IHRvIHRoZSBjbGFzcyBzaG9ydGx5LgoKV2Ugd2lsbCBhbHNvIHNlbmQgb3V0IGEgdmlkZW8gb2YgdGhpcyB3b3Jrc2hvcC4KCiMjIyMgUGxlYXNlIFByb3ZpZGUgRmVlZGJhY2sKCkphc29uIGFuZCBJIGhvcGUgdG8gY29udGludWUgZGV2ZWxvcGluZyB0aGlzIHByYWN0aWNhbCBtYXRlcmlhbCB0byBwcm92aWRlIG1vcmUgaGFuZHMtb24gZXhwZXJpZW5jZSBpbiB0aGUgZnV0dXJlLCBzbyBhbnkgZmVlZGJhY2sgb24gdGhlIHRvb2xzIHlvdSB3b3VsZCBsaWtlIHRvIGV4cGxvcmUgaXMgYXBwcmVjaWF0ZWQuCgoKCgoKCg==